package com.zhtooles.config.mybatis;

import com.zhtools.EnumCode;
import org.apache.commons.lang.StringUtils;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.annotation.MapperScan;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.transaction.annotation.TransactionManagementConfigurer;
import org.springframework.util.CollectionUtils;

import javax.sql.DataSource;
import java.io.IOException;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;

/**
 * Created by zhanghao on 2017/7/25.
 */
@Configuration
// @MapperScan(value = {"com.zhservice.**.dao"})
@EnableTransactionManagement
public class MyBatisConfig implements TransactionManagementConfigurer {
    private static final Logger LOGGER = LoggerFactory.getLogger(MyBatisConfig.class);

    private static final String REGEX = ".*target/classes/|.*target.test-classes.|.*jar!/|.*BOOT-INF/classes!/";
    private static final String REPLACEMENT = "";

    @Autowired
    DataSource dataSource;
    @Value("${mybatis.config.location:mybatisConfig.xml}")
    private String mybatisConfigLocation;
    @Value("${mybatis.config.enum.locations}")
    private List<String> enumClassLocations;

    private static final String LOG_NOT_CONFIG_ENUM_CLASS_LOCATIONS = ">>> 尚未配置枚举类路径!";
    private static final String LOG_SCAN_ENUM_CLASS_LOCATION = ">>> 扫描枚举类路径:{}";

    public MyBatisConfig() {
        LOGGER.info("*************************MyBatis Config****************************");
    }

    private String replace(URI uri) {
        String clazzName = uri.toString().replaceAll(REGEX, REPLACEMENT);
        return clazzName;
    }

    private List<String> list() throws IOException {
        List<String> result = new ArrayList<>();
        if (CollectionUtils.isEmpty(enumClassLocations)) {
            LOGGER.info(LOG_NOT_CONFIG_ENUM_CLASS_LOCATIONS);
            return result;
        }
        for (String location : enumClassLocations) {
            String scanPath = "classpath*:" + location + "/*.class";
            LOGGER.info(LOG_SCAN_ENUM_CLASS_LOCATION, scanPath);

            ResourcePatternResolver resourceResolver = new PathMatchingResourcePatternResolver();
            Resource[] resources = resourceResolver.getResources(scanPath);
            for (Resource resource : resources) {
                URI uri = resource.getURI();
                String clazzName = replace(uri);
                clazzName = clazzName.replace('/', '.').replaceAll("\\.class", "");
                result.add(clazzName);
            }
        }
        return result;
    }

    @Bean(name = {"sqlSessionFactory"})
    public SqlSessionFactory sqlSessionFactoryBean() throws IOException {
        SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
        bean.setDataSource(this.dataSource);
        if (StringUtils.isNotBlank(this.mybatisConfigLocation)) {
            bean.setConfigLocation(new ClassPathResource(this.mybatisConfigLocation));
        }
        try {
            SqlSessionFactory sqlSessionFactory = bean.getObject();
            List<String> classNames = list();
            if (!CollectionUtils.isEmpty(classNames)) {
                for (String className : classNames) {
                    Class<?> aClass = Class.forName(className, false, getClass().getClassLoader());
                    if (aClass.isEnum() && EnumCode.class.isAssignableFrom(aClass)) {
                        sqlSessionFactory.getConfiguration().getTypeHandlerRegistry().register(aClass, CodeEnumTypeHandler.class);
                    }
                }
            }
            return sqlSessionFactory;
        } catch (Exception var4) {
            var4.printStackTrace();
            throw new RuntimeException(var4);
        }
    }

    @Bean
    public SqlSessionTemplate sqlSessionTemplate(SqlSessionFactory sqlSessionFactory) {
        return new SqlSessionTemplate(sqlSessionFactory);
    }

    @Bean
    public PlatformTransactionManager annotationDrivenTransactionManager() {
        return new DataSourceTransactionManager(this.dataSource);
    }
}
